import crypto from 'crypto';
import { app } from 'electron';
import fs from 'fs';
import jwt from 'jsonwebtoken';
import { mkdirp } from 'mkdirp';
import os from 'os';
import path from 'path';

import { Env } from './env';

const USER_PREF = 'JT_';
const USERS_FILE = '.users';
const DEFAULT_USER_NAME = '系统管理员';

interface UserInfo {
  id: string;
  name: string;
  isAdmin: boolean;
}

// JWT token接口
interface JWTPayload {
  userId: string;
  userName: string;
  iat?: number;
}

/**
 * 登录用户信息接口
 */
interface LoggedInUserInfo {
  lockFd: number; // 锁文件描述符
  token: string; // 登录时的JWT token
  loginTime: number; // 登录时间戳
}

class UserManager {
  // 多用户锁管理 - 现在包含token信息
  private loggedInUsers: Map<string, LoggedInUserInfo> = new Map(); // userId -> LoggedInUserInfo

  // JWT secret
  private jwtSecret: string;

  constructor() {
    // 使用随机UUID作为JWT密钥，每次启动都生成新的密钥
    this.jwtSecret = crypto.randomUUID().replace(/-/g, '');
  }

  /**
   * 获取用户系统根目录
   */
  private async getRuntimeDir(): Promise<string> {
    const runtimeDir = await Env.getRuntimeDir();
    return runtimeDir;
  }

  /**
   * .users 文件路径
   */
  private async getUsersFilePath(): Promise<string> {
    const systemDir = await this.getRuntimeDir();
    return path.join(systemDir, USERS_FILE);
  }

  /**
   * 获取用户锁文件路径
   */
  private async getUserLockFile(userId: string): Promise<string> {
    const usersRootDir = await this.getRuntimeDir();
    return path.join(usersRootDir, `${userId}.lock`);
  }

  /**
   * 获取用户工作区目录
   * @param userId 用户ID
   * @returns 用户工作区目录
   */
  private async getUserWorkspaceDir(userId: string): Promise<string> {
    const workspaceDir = await Env.getWorkspacePath();
    const userWorkspaceDir = path.join(workspaceDir, userId);
    if (!fs.existsSync(userWorkspaceDir)) {
      await mkdirp(userWorkspaceDir);
    }
    return userWorkspaceDir;
  }

  /**
   * 获取本机MAC地址（同步，取第一个网卡）
   */
  private getMacAddress(): string {
    const interfaces = os.networkInterfaces();
    for (const name of Object.keys(interfaces)) {
      for (const iface of interfaces[name]!) {
        if (!iface.internal && iface.mac && iface.mac !== '00:00:00:00:00:00') {
          // 移除所有分隔符（冒号和连字符），确保在所有操作系统下都是有效的文件名
          return iface.mac.replace(/[-:]/g, '').toLowerCase();
        }
      }
    }
    return 'unknownmac';
  }

  /**
   * 生成盐
   */
  private generateSalt(length = 8): Buffer {
    return crypto.randomBytes(length);
  }

  /**
   * 生成用户ID
   */
  private genUserID(): string {
    const mac = this.getMacAddress();
    const salt = this.generateSalt(8);
    const file = app.getPath('exe');
    const hash = crypto.createHash('md5').update(Buffer.from(file)).update(salt).digest('hex');
    const short = hash.slice(0, 8);
    return USER_PREF + mac + '_' + short;
  }

  /**
   * 读取 .users 文件（带锁保护）
   */
  private async readUsersFile(): Promise<{ users: Array<UserInfo> }> {
    const file = await this.getUsersFilePath();
    const lockFile = file + '.lock';

    // 等待写入锁释放
    await this.waitForLockRelease(lockFile);

    if (fs.existsSync(file)) {
      try {
        const data = JSON.parse(fs.readFileSync(file, 'utf-8'));
        // 兼容旧格式，移除current字段
        return { users: data.users || [] };
      } catch (error) {
        console.warn('读取用户文件失败，使用默认配置:', error);
        return { users: [] };
      }
    } else {
      return { users: [] };
    }
  }

  /**
   * 等待锁文件释放
   */
  private async waitForLockRelease(lockFile: string, maxWaitTime: number = 5000): Promise<void> {
    const startTime = Date.now();
    const checkInterval = 50; // 50ms检查一次

    while (fs.existsSync(lockFile)) {
      if (Date.now() - startTime > maxWaitTime) {
        console.warn('等待锁文件释放超时，强制继续');
        break;
      }
      await new Promise((resolve) => setTimeout(resolve, checkInterval));
    }
  }

  /**
   * 写入 .users 文件（带文件锁保护）
   */
  private async writeUsersFile(data: { users: Array<UserInfo> }): Promise<void> {
    const file = await this.getUsersFilePath();
    const lockFile = file + '.lock';

    // 最多重试3次
    const maxRetries = 3;
    for (let attempt = 1; attempt <= maxRetries; attempt++) {
      let lockFd: number | null = null;

      try {
        // 尝试创建锁文件
        lockFd = fs.openSync(lockFile, 'wx');

        // 写入数据
        fs.writeFileSync(file, JSON.stringify(data, null, 2), 'utf-8');

        // 成功写入，退出循环
        break;
      } catch (error: any) {
        if (error.code === 'EEXIST' && attempt < maxRetries) {
          // 锁文件存在且未达到最大重试次数，等待后重试
          await new Promise((resolve) => setTimeout(resolve, 100 * attempt));
          continue;
        } else if (error.code === 'EEXIST') {
          // 达到最大重试次数
          throw new Error(`写入用户文件失败：文件被锁定，已重试 ${maxRetries} 次`);
        } else {
          // 其他错误
          throw error;
        }
      } finally {
        // 确保释放锁文件
        if (lockFd !== null) {
          try {
            fs.closeSync(lockFd);
            fs.unlinkSync(lockFile);
          } catch (cleanupError) {
            console.warn('清理写入锁文件失败:', cleanupError);
          }
        }
      }
    }
  }

  /**
   * 初始化用户系统（如无用户则创建初始用户）
   */
  async initUsers(): Promise<void> {
    let data = await this.readUsersFile();
    if (!data.users.length) {
      const id = this.genUserID();
      data = { users: [{ id, name: DEFAULT_USER_NAME, isAdmin: true }] };
      await this.writeUsersFile(data);
      await this.getUserWorkspaceDir(id);
    }
  }

  /**
   * 创建新用户
   */
  async createUser(name: string): Promise<string> {
    const data = await this.readUsersFile();
    const id = this.genUserID();
    data.users.push({ id, name, isAdmin: false });
    await this.writeUsersFile(data);
    await this.getUserWorkspaceDir(id);
    return id;
  }

  /**
   * 获取所有用户
   */
  async getAllUsers(): Promise<Array<UserInfo>> {
    const data = await this.readUsersFile();
    return data.users;
  }

  /**
   * 获取指定用户的工作区目录
   * @param userId 用户ID
   * @returns 用户工作区目录路径，如果用户不存在返回null
   */
  async getUserWorkspace(userId: string): Promise<string | null> {
    const users = await this.getAllUsers();
    const user = users.find((u) => u.id === userId);
    if (!user) {
      return null; // 用户不存在
    }
    return await this.getUserWorkspaceDir(userId);
  }

  /**
   * 登录并加锁，失败抛异常，成功返回JWT token
   */
  async login(userId: string): Promise<string> {
    // 检查用户是否已经登录
    if (this.loggedInUsers.has(userId)) {
      throw new Error('用户已经登录');
    }

    // 验证用户是否存在
    const users = await this.getAllUsers();
    const user = users.find((u) => u.id === userId);
    if (!user) {
      throw new Error('用户不存在');
    }

    // 尝试加锁
    const lockFile = await this.getUserLockFile(userId);
    let fd: number;
    try {
      fd = fs.openSync(lockFile, 'wx');
    } catch (err: any) {
      if (err.code === 'EEXIST') {
        throw new Error('该用户已在其他实例登录，无法重复登录');
      }
      throw err;
    }

    // 添加到已登录用户列表
    this.loggedInUsers.set(userId, {
      lockFd: fd,
      token: '', // 先设置为空，生成token后更新
      loginTime: Date.now()
    });

    // 生成JWT token
    const payload: JWTPayload = {
      userId: user.id,
      userName: user.name
    };

    const token = jwt.sign(payload, this.jwtSecret);

    // 更新用户信息中的token
    const userInfo = this.loggedInUsers.get(userId)!;
    userInfo.token = token;

    return token;
  }

  /**
   * 验证JWT token
   * 不仅验证token的有效性，还验证token是否属于当前已登录的用户
   */
  verifyToken(token: string): boolean {
    try {
      // 第一步：验证token的格式和签名
      const decoded = jwt.verify(token, this.jwtSecret) as JWTPayload;

      // 第二步：验证token是否属于当前已登录的用户
      const loggedInUserInfo = this.loggedInUsers.get(decoded.userId);
      if (!loggedInUserInfo) {
        console.warn('Token验证失败: 用户未登录');
        return false;
      }

      // 第三步：验证token是否与登录时的token一致
      if (loggedInUserInfo.token !== token) {
        console.warn('Token验证失败: Token与登录时的token不匹配');
        return false;
      }

      return true;
    } catch (error) {
      console.warn('JWT token验证失败:', error);
      return false;
    }
  }

  /**
   * 获取JWT token的payload（内部方法）
   */
  private getTokenPayload(token: string): JWTPayload | null {
    try {
      const decoded = jwt.verify(token, this.jwtSecret) as JWTPayload;
      return decoded;
    } catch {
      return null;
    }
  }

  /**
   * 从token中获取用户信息
   */
  getUserFromToken(token: string): { id: string; name: string } | null {
    const payload = this.getTokenPayload(token);
    if (!payload) {
      return null;
    }

    return {
      id: payload.userId,
      name: payload.userName
    };
  }

  /**
   * 注销当前用户（释放锁）
   */
  async logout(userId: string): Promise<void> {
    const loggedInUserInfo = this.loggedInUsers.get(userId);
    if (!loggedInUserInfo) {
      return; // 用户未登录
    }

    try {
      fs.closeSync(loggedInUserInfo.lockFd);
    } catch {
      // ignore error
    }

    try {
      const lockFile = await this.getUserLockFile(userId);
      fs.unlinkSync(lockFile);
    } catch {
      // ignore error
    }

    // 从已登录列表中移除
    this.loggedInUsers.delete(userId);
  }

  /**
   * 获取所有已登录的用户
   */
  getLoggedInUsers(): string[] {
    return Array.from(this.loggedInUsers.keys());
  }

  /**
   * 获取已登录用户数量
   */
  getLoggedInUserCount(): number {
    return this.loggedInUsers.size;
  }

  /**
   * 检查用户是否在当前实例中登录
   */
  isUserLoggedInLocally(userId: string): boolean {
    return this.loggedInUsers.has(userId);
  }

  /**
   * 获取用户的登录token
   */
  getUserToken(userId: string): string | null {
    const userInfo = this.loggedInUsers.get(userId);
    return userInfo ? userInfo.token : null;
  }

  /**
   * 获取用户的登录时间
   */
  getUserLoginTime(userId: string): number | null {
    const userInfo = this.loggedInUsers.get(userId);
    return userInfo ? userInfo.loginTime : null;
  }

  /**
   * 获取所有已登录用户的详细信息
   */
  getLoggedInUsersInfo(): Array<{
    userId: string;
    token: string;
    loginTime: number;
    loginTimeFormatted: string;
  }> {
    const result: Array<{
      userId: string;
      token: string;
      loginTime: number;
      loginTimeFormatted: string;
    }> = [];

    for (const [userId, userInfo] of this.loggedInUsers) {
      result.push({
        userId,
        token: userInfo.token,
        loginTime: userInfo.loginTime,
        loginTimeFormatted: new Date(userInfo.loginTime).toLocaleString()
      });
    }

    return result;
  }

  /**
   * 注销所有用户
   */
  async logoutAll(): Promise<void> {
    const userIds = Array.from(this.loggedInUsers.keys());
    for (const userId of userIds) {
      await this.logout(userId);
    }
  }

  /**
   * 检查用户是否已被锁定（已登录）
   */
  async isUserLocked(userId: string): Promise<boolean> {
    const lockFile = await this.getUserLockFile(userId);
    return fs.existsSync(lockFile);
  }

  /**
   * 删除用户
   */
  async deleteUser(userId: string): Promise<boolean> {
    const data = await this.readUsersFile();
    const userIndex = data.users.findIndex((u) => u.id === userId);

    if (userIndex === -1) {
      return false; // 用户不存在
    }

    // 如果用户已登录，先注销
    if (this.isUserLoggedInLocally(userId)) {
      await this.logout(userId);
    }

    // 如果用户在其他实例中被锁定，不允许删除
    if (await this.isUserLocked(userId)) {
      throw new Error('用户正在其他实例中使用，无法删除');
    }

    // 删除用户记录
    data.users.splice(userIndex, 1);

    await this.writeUsersFile(data);

    // 删除用户目录
    try {
      const userDir = await this.getUserWorkspaceDir(userId);
      if (fs.existsSync(userDir)) {
        fs.rmSync(userDir, { recursive: true, force: true });
      }
    } catch (error) {
      console.warn(`删除用户目录失败: ${error}`);
    }

    return true;
  }

  /**
   * 重命名用户
   */
  async renameUser(userId: string, newName: string): Promise<boolean> {
    const data = await this.readUsersFile();
    const user = data.users.find((u) => u.id === userId);

    if (!user) {
      return false; // 用户不存在
    }

    user.name = newName;
    await this.writeUsersFile(data);
    return true;
  }

  /**
   * 获取用户统计信息
   */
  async getUserStats(): Promise<{
    totalUsers: number;
    lockedUsers: string[];
    loggedInUsers: string[];
    loggedInUserCount: number;
  }> {
    const users = await this.getAllUsers();
    const lockedUsers: string[] = [];

    // 检查每个用户的锁定状态
    for (const user of users) {
      if (await this.isUserLocked(user.id)) {
        lockedUsers.push(user.id);
      }
    }

    return {
      totalUsers: users.length,
      lockedUsers,
      loggedInUsers: this.getLoggedInUsers(),
      loggedInUserCount: this.getLoggedInUserCount()
    };
  }

  /**
   * 清理所有锁文件（应用启动时调用）
   * 包括用户锁文件和文件写入锁
   */
  async cleanupLocks(): Promise<void> {
    try {
      // 清理本地登录状态
      this.loggedInUsers.clear();

      // 清理用户锁文件
      const usersRootDir = await this.getRuntimeDir();
      if (fs.existsSync(usersRootDir)) {
        const files = fs.readdirSync(usersRootDir);
        for (const file of files) {
          if (file.endsWith('.lock')) {
            const lockFile = path.join(usersRootDir, file);
            try {
              fs.unlinkSync(lockFile);
            } catch {
              // ignore error
            }
          }
        }
      }

      // 清理文件写入锁
      try {
        const usersFile = await this.getUsersFilePath();
        const writeLockFile = usersFile + '.lock';
        if (fs.existsSync(writeLockFile)) {
          fs.unlinkSync(writeLockFile);
        }
      } catch (error) {
        console.warn('清理文件写入锁失败:', error);
      }
    } catch (error) {
      console.warn(`清理锁文件失败: ${error}`);
    }
  }
}

// 创建单例实例
const userManager = new UserManager();

// 导出 UserManager 类和单例实例
export { UserManager };
export default userManager;
